/* ----------------------------------------------------------------------------
* File: user_box.h
*
* Desc: Declaration of CUserBox class
*
* Created: 19/02/2011, by Alexey Korshunov
* ---------------------------------------------------------------------------- */
#ifndef _USER_BOX_H_
#define _USER_BOX_H_

#include "user_profile.h"
#include "box_connection.h"
#include "map_thread_safe.h"


class CUserBox;
class CBoxServer;
class CBoxConnection;

typedef std::map<std::string, file_info*>				MapFiles;

typedef struct box_environment
{
	box_environment() : box(NULL), logger(NULL), stop(false), opened(false)
	{
		pthread_mutex_init(&mutex_map, NULL);

		pthread_cond_init(&cv_change, NULL);
		pthread_mutex_init(&mutex_change, NULL);

		pthread_cond_init(&cv_start, NULL);
		pthread_mutex_init(&mutex_start, NULL);

		pthread_cond_init(&cv_stop, NULL);
		pthread_mutex_init(&mutex_stop, NULL);
	}

	~box_environment()
	{
		pthread_mutex_destroy(&mutex_map);

		pthread_cond_destroy(&cv_change);
		pthread_mutex_destroy(&mutex_change);

		pthread_cond_destroy(&cv_start);
		pthread_mutex_destroy(&mutex_start);

		pthread_cond_destroy(&cv_stop);
		pthread_mutex_destroy(&mutex_stop);
	}

	CUserBox *box;
	CFileLogger *logger;
	MapFiles map_files;
	pthread_mutex_t mutex_map;
	bool stop;
	bool opened;

	pthread_cond_t cv_change;
	pthread_mutex_t mutex_change;

	pthread_cond_t cv_start;
	pthread_mutex_t mutex_start;

	pthread_cond_t cv_stop;
	pthread_mutex_t mutex_stop;

}box_environment;

/************************************************************************/
/*	CUserBox class to store info about one user box                     */
/************************************************************************/
class CUserBox
{
public:
	/************************************************************************/
	/*	CUserFile class to control user file								*/
	/************************************************************************/
	class CUserFile
	{
	public:
		CUserFile(const char* file, const char* mode) throw (std::exception);
		~CUserFile();

		int Reset();
		bool IsEof() const { return m_eof; }
		size_t GetSize() const { return m_size; }
		size_t ReadData(unsigned char* data, size_t size);
		size_t WriteData(unsigned char* data, size_t size);

	private:
		const char* m_file_name;
		const char* m_mode;
		FILE* m_fp;
		bool m_eof;
		size_t m_size;
	};

private:

	// Lock copy constructor and assignment operator
	CUserBox(const CUserBox&);
	CUserBox& operator=(const CUserBox&);

	typedef std::vector<CBoxConnection*>			VectorSubscribers;

public:
	CUserBox(CBoxServer* parent);
	~CUserBox();

	// Open box
	int Open(const char *username, unsigned int id);
	// Close box
	int Close();

	// Add file into the box
	int AddFile(file_info* finfo);
	// Delete file from box
	int DeleteFileByName(const char* name);
	// Get count of files
	size_t CountFiles();
	// Get file info by identifier
	const file_info* GetFileInfoById(unsigned int id);
	// Get file info by name
	const file_info* GetFileInfoByName(const char* name);

	
	// Read file map
	int ReadMap();
	// Get vector of changed files
	std::vector<file_info*>* GetChangedFiles();
	// Notify subscribers about changes
	void NotifySubscribers(std::vector<file_info*> *finfo_vector);


	// Add subscriber of this box
	void AddSubscriber(CBoxConnection* obj);
	// Delete subscriber
	void DeleteSubscriber(CBoxConnection* obj);
	// Get count subscribers
	size_t CountSubscribers();

	// Get profile info
	const user_profile* GetProfileInfo();
	// Get identifier
	unsigned int GetId() const { return m_id; }
	// Get logger
	CFileLogger* GetLogger() const { return m_env.logger; }

private:
	// Log entry
	//static void LogEntry(const char *msg,...);

	unsigned int m_id;
	pthread_t m_thread_change;
	box_environment m_env;
	IUserProfile *m_user_profile;

	VectorSubscribers m_subscribers;
	pthread_mutex_t m_mutex_subscriber;
};


class CMapUserBox : public CMapThreadSafe<CUserBox*>
{
public:
	CUserBox* FindBoxByUserName(const char *name)
	{
		if (name != NULL)
		{
			CMutexLocker lock(m_mutex_access);
			std::map<unsigned int, CUserBox*>::iterator it = m_map.begin();
			for (; it != m_map.end(); ++it)
			{
				if (!strcmp(it->second->GetProfileInfo()->username, name))
					return it->second;
			}
		}
		return NULL;
	}

	CUserBox* FindBoxById(unsigned int id)
	{
		std::map<unsigned int, CUserBox*>::iterator it;

		CMutexLocker lock(m_mutex_access);
		it = m_map.find(id);
		if (it != m_map.end())
			return it->second;
		else
			return NULL;
	}
};

#endif // _USER_BOX_H_